{-- 
    Composition of two applicative functors _f_ and _g_
    such that the type _f (g a)_ can itself be treated
    as applicative functor.
-}
package Data.Compose where

data Compose f g a = Compose { run :: f (g a) }

compose :: f (g a) -> Compose f g a
compose = Compose

instance (Functor f, Functor g) => Functor (Compose f g) where
  fmap f (Compose fga) = Compose (fmap (fmap f) fga)

instance (Applicative f, Applicative g) => Applicative (Compose f g) where
  pure a = Compose (pure (pure a))
  Compose fgf <*> Compose fga = Compose ((<*>) <$> fgf <*> fga)